package com.yicheng.statistics.actor.analysis

import com.yicheng.statistics.actor.SaveHtaData

import akka.actor.Actor
import akka.actor.ActorLogging
import akka.actor.ActorRef
import akka.actor.Props
import com.yicheng.statistics.common.HTADB
import com.yicheng.statistics.service.HTAService
import com.yicheng.statistics.repo.cassandra.DataInfoDB
import com.yicheng.statistics.common.TimeUtils
import scala.util.Failure
import scala.util.Success
import java.util.Date
import com.yicheng.statistics.common.RTAModel.VehicleTiredSetting
import org.joda.time.DateTime
import com.yicheng.statistics.repo.RTAModel.VehicleTired
import com.yicheng.statistics.repo.model.Data.DataInfo
import com.carcloud.gateway.bean.data.DataVehPos
import com.carcloud.gateway.bean.data.DataVehOverall
import com.yicheng.statistics.actor.AnalysisParser
import akka.actor.SupervisorStrategy.Stop

/**
 * 疲劳驾驶统计
 */
class TriedDrive extends Actor with ActorLogging with AnalysisParser{
  
  val saveHtaDataActor:ActorRef = context.child("saveHtaData").
    getOrElse(context.actorOf(Props[SaveHtaData], "saveHtaData"))
  
  import scala.concurrent.ExecutionContext.Implicits.global
  def receive: Receive = {
    case (deviceId:String,deviceType:Int, analyseGroupId:Long) =>
      log.info("疲劳驾驶 deviceId "+deviceId)
      val tiredTimeState = TiredTimeState(false, true, None, None,Some(0), Some(0),Some(0), None,None, None,None, 0, false, None)
      val mileageState = MileageState(None, None, Some(0), None, None, None, None)
      val tiredState = TiredState(tiredTimeState, mileageState, deviceId, deviceType)
      
      HTADB.getVehicleTiredSettings(analyseGroupId).map(s => 
        if( !s.headOption.isEmpty){
          parseOneDayDataInfo(deviceType, deviceId, tiredState, s.headOption.get, Parser _)
        }
        
      )
    case Stop =>
      //context.parent ! Stop
      log.info("tireddrive stop")
      context.actorSelection("/user/daemon") ! TiredStop
    case _ => log.info("TriedDrive")
  }
  
  type S = VehicleTiredSetting
  /**
   * 解析疲劳驾驶
   * 1 存储数据到时间报警
   */
  def Parser(state:TiredState, setting:VehicleTiredSetting , dataInfos : Seq[DataInfo], isEnd:Boolean): TiredState = {
    
    var tiredTimeState:TiredTimeState = state.tiredTimeState//
    var mileageState : MileageState = state.mileageState//
    var vehicleTired: VehicleTired = VehicleTired(
        state.deviceType, state.deviceId, None, None, None, None, 
        None, None, None, None, None, None,
        None, None, None, None, DateTime.now().toDate(), None)
    
    val deviceId = state.deviceId
    val deviceType = state.deviceType
    val dayTimeWarnning =  setting.timeThreshold - setting.earlyWarningThreshold//提前预警时间
    val dayWarnnigStartTime = TimeUtils.time2DateTime(setting.startTime, TimeUtils.getPreDateTime()).toDate().getTime()
    val dayWarnnigEndTime = TimeUtils.time2DateTime(setting.endTime, TimeUtils.getPreDateTime()).toDate().getTime()
    var timeThreshold = setting.timeThreshold
    log.info(dataInfos.toString())
    dataInfos.foreach( di => {
      val posData: DataVehPos = di.data_vehicle.posData.get
      val overAllData: DataVehOverall = di.data_vehicle.overallData.get
      
      //夜间间行车
      if(TimeUtils.inTimeRang(setting.nightDriveBeginTime.get, setting.nightDriveendTime.get, di.data_time)){
        timeThreshold = setting.nightTimeThreshold.get
      }
      //日间行车
      if( TimeUtils.inTimeRang(setting.startTime, setting.endTime, di.data_time)){
        timeThreshold = setting.timeThreshold
      }
      
      if(!tiredTimeState.start) {//是否记录第一条数据
        tiredTimeState = tiredTimeState.copy(start = true, startTime = Some(di.data_time), lastData = Some(di))
        mileageState = mileageState.copy(
            totalStartMileage = Some(overAllData.currentMileage),
            driveStartMileage = Some(overAllData.currentMileage))
      }else{
        
        //1如果两条数据间隔时间比较长，当大于休息时长的时候 如果报警中 消除报警 
        val restTime = TimeUtils.secondsBetweenTime(tiredTimeState.lastData.get.data_time, di.data_time)
        if( restTime > setting.effectiveRestTime){
          
          if(tiredTimeState.firestAlramFlag){//是第一次报警 记录第一次报警的开始时间是地点
            //记录统计数据的第一次报警的开始时间 开始坐标
            vehicleTired = vehicleTired.copy(
              startdatetime = tiredTimeState.startTime, 
              startlon = tiredTimeState.startLon, 
              startlat = tiredTimeState.endLat)
          }
          
          if( tiredTimeState.state ){//报警中 消除报警 计算报警总时长
            tiredTimeState = tiredTimeState.copy(
              startTime = Some(di.data_time),
              startLat = posData.latitude,
              startLon = posData.longitude,
              state = false, 
              restTotalTime = Some(tiredTimeState.restTotalTime.get + restTime),
              totalTime = Some(0) ,
              alarmTotalTime = Some( tiredTimeState.alarmTotalTime.get + TimeUtils.secondsBetweenTime(tiredTimeState.endTime.get, tiredTimeState.startTime.get)))//消除报警
              
            //报警结束 记录结束的地点时间
            vehicleTired = vehicleTired.copy(
              enddatetime = Some(di.data_time), 
              endlon = posData.longitude, 
              endlat = posData.latitude)
           
            val currentAlarmMileage = overAllData.currentMileage - mileageState.startMileage.get//单位是km/h
            //计算报警结束的里程
            mileageState = mileageState.copy(
                driveStartMileage = Some(overAllData.currentMileage),
                startMileage = Some(overAllData.currentMileage),
                alarmTotalMileage = Some(mileageState.alarmTotalMileage.get + currentAlarmMileage))
          }else{//没有报警清理数据，开始新一论的统计  计算休息的总时长
            tiredTimeState = tiredTimeState.copy(
              startTime = Some(di.data_time),
              startLat = posData.latitude,
              startLon = posData.longitude,
              state = false, 
              restTotalTime = Some(tiredTimeState.restTotalTime.get + restTime),
              totalTime = Some(0))
            //重新开始计算行驶里程 设置行驶里程的初始值
            mileageState = mileageState.copy(
                driveStartMileage = Some(overAllData.currentMileage))
          }
        }//1如果休息时长不够继续下面的判断
        
        if( (tiredTimeState.totalTime.get > timeThreshold)
            && (mileageState.driveMileage.get > setting.minDistance) ){//如果大于时间阀值并且行驶的距离大于行驶最小距离 开始计算报警的统计
          log.info("开始计算报警 ")
          if(tiredTimeState.state){//继续计算超速的数据
            tiredTimeState = tiredTimeState.copy(
              totalTime = Some(di.data_time.getTime - tiredTimeState.startTime.get.getTime))//当前运行的时间继续增加
          }else{
            //设置对象处于报警状态
            tiredTimeState = tiredTimeState.copy(//处于报警状态
              startTime = Some(di.data_time),
              startLat = posData.latitude,
              startLon = posData.longitude,
              endTime = Some(di.data_time), 
              totalTime = Some(di.data_time.getTime - tiredTimeState.startTime.get.getTime),
              count = tiredTimeState.count + 1,
              state = true)
              
            mileageState = mileageState.copy(
              startMileage = Some(overAllData.currentMileage),
              totalMileage = Some(0),
              alarmTotalMileage = Some(0))
          }
          
        }else{//没有超过时间阀值 继续增行驶时间 增加行驶里程
          tiredTimeState = tiredTimeState.copy(
            endTime = Some(di.data_time),
            endLat = posData.latitude,
            endLon = posData.longitude,
            totalTime = Some(di.data_time.getTime - tiredTimeState.startTime.get.getTime))
          
          //计算行驶里程
          mileageState = mileageState.copy(driveMileage = Some(overAllData.currentMileage - mileageState.driveStartMileage.get))
        }
        
      }
    })
    
    if(tiredTimeState.state && isEnd){//全部数据解析完毕 如果处在报警中 记录最后一次的位置时间  报警次数加一 报警时间增加
      //报警结束 记录结束的地点时间
      vehicleTired = vehicleTired.copy(
        mileagethreshold = Some(0),
        timethreshold = Some(setting.timeThreshold),
        totaltime = Some(tiredTimeState.alarmTotalTime.get.toInt),
        enddatetime = tiredTimeState.endTime, 
        endlon = tiredTimeState.endLon, 
        endlat = tiredTimeState.endLat,
        startmileage = mileageState.startMileage,
        endmileage = mileageState.endMileage,
        totalmileage = mileageState.alarmTotalMileage,
        analysegroupsid = Some(setting.analyseGroupsID.toInt),
        analyseconditions = Some(""),
        createdatetime = DateTime.now().toDate())
    }
    //保存数据库
    saveHtaDataActor ! vehicleTired
    TiredState(tiredTimeState, mileageState, deviceId, deviceType)
  }
}

/**
 * 疲劳驾驶时间数据状态存储
 */
case class TiredTimeState(
    start:Boolean,//是否开始报警
    firestAlramFlag:Boolean,//第一次报警标志
    startTime:Option[Date],//报警开始时间
    endTime:Option[Date],//报警结束时间
    totalTime:Option[Long],//累计行驶时间
    restTotalTime:Option[Long],//休息总时长
    alarmTotalTime:Option[Long],//报警总时长
    startLat:Option[Double],//第一次报警开始纬度
    startLon:Option[Double],//第一次报警开始精度
    endLat:Option[Double],//最后一次报警结束纬度
    endLon:Option[Double],//最后一次报警结束精度
    count:Int,//报警次数
    state:Boolean,
    lastData:Option[DataInfo])
    
case class MileageState(
  totalStartMileage:Option[Int],//计算一天总里程开始数据
  driveStartMileage:Option[Int],//每次行驶开始里程
  driveMileage:Option[Int],//行驶里程，每次休息完重新记录表显里程
  startMileage:Option[Int],//报警开始里程
  endMileage:Option[Int],//报警结束里程
  totalMileage:Option[Int],//行驶总里程
  alarmTotalMileage:Option[Int])//报警总里程

case class TiredState(tiredTimeState:TiredTimeState, mileageState:MileageState, deviceId:String, deviceType:Int)